package com.junlinpro.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.junlinpro.OpusSdk;
import com.junlinpro.entity.MessageEntity;
import com.junlinpro.utils.ByteUtil;
import com.junlinpro.utils.Constant;
import com.junlinpro.utils.HBaseUtil;
import com.junlinpro.utils.KafkaProducerUtil;
import com.junlinpro.utils.OpusSdkProvider;
import com.junlinpro.utils.UdpMapData;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class TimingAudioService {

    @Autowired
    OpusSdk opusSdk;

    @Autowired
    private UdpMapData udpMapData;

    Map<String, HashMap<Integer, byte[]>> channelQueue = new HashMap<String, HashMap<Integer, byte[]>>();
    Map<String, HashMap<Integer, byte[]>> alarmQueue = new HashMap<String, HashMap<Integer, byte[]>>();


    /**
     * 判断当前数据是否可以进行存储
     *
     * @param cardKey  redis储存的 key
     * @param utcTime  utc时间
     * @param dataType 数据类型（1：定时上传 2：报警数据）
     */
    //@Async
    public synchronized boolean dataIsAdd(String cardKey, String utcTime, int dataType) {
        // 返回值
        boolean isAdd = false;
        isAdd = true;
//        return true;

//        String redisKey = "audio_map_" + cardKey;
//
//        if (redisTemplate.opsForHash().entries(redisKey).size() > 0) {
//
//            Map<String, String> resultMap = redisTemplate.opsForHash().entries(redisKey);
//
//            // 如果传入类型为定时的，比较当前时间和缓存的时间，并取报警的缓存时间再次存入缓存中。
//            if (dataType == 1) {
//                if (resultMap.get("timing") != null) {
//                    // 缓存中的utc时间
//                    Long cacheUtc = Long.valueOf(resultMap.get("timing"));
//                    // 当前utc时间
//                    Long nowUtc = Long.valueOf(utcTime);
//                    // 如果当前时间大于缓存中的时间并且不相等说明为有效数据
//                    if (nowUtc > cacheUtc && nowUtc != cacheUtc) {
//                        // 将值放入redis
//                        resultMap.put("timing", nowUtc.toString());
//                        if (resultMap.get("alarm") != null) {
//                            resultMap.put("alarm", resultMap.get("alarm"));
//                        }
//                        redisTemplate.opsForHash().putAll(redisKey, resultMap);
//                        // 设置过期时间
//                        redisTemplate.expire(redisKey, 2, TimeUnit.DAYS);
//                        isAdd = true;
//                    } else {
//                        // 设置过期时间
//                        redisTemplate.expire(redisKey, 2, TimeUnit.DAYS);
//                    }
//                } else {
//                    resultMap.put("timing", utcTime);
//                    redisTemplate.opsForHash().putAll(redisKey, resultMap);
//                    // 设置过期时间
//                    redisTemplate.expire(redisKey, 2, TimeUnit.DAYS);
//                    isAdd = true;
//                }
//            } else if (dataType == 2) {
//
//                if (resultMap.get("alarm") != null) {
//
//                    // 缓存中的utc时间
//                    Long cacheUtc = Long.valueOf(resultMap.get("alarm"));
//                    // 当前utc时间
//                    Long nowUtc = Long.valueOf(utcTime);
//
//                    if (nowUtc > cacheUtc && nowUtc != cacheUtc) {
//                        // 将值放入redis
//                        resultMap.put("alarm", nowUtc.toString());
//                        if (resultMap.get("timing") != null) {
//                            resultMap.put("timing", resultMap.get("timing"));
//                        }
//                        redisTemplate.opsForHash().putAll(redisKey, resultMap);
//                        // 设置过期时间
//                        redisTemplate.expire(redisKey, 2, TimeUnit.DAYS);
//                        isAdd = true;
//                    } else {
//                        // 设置过期时间
//                        redisTemplate.expire(redisKey, 2, TimeUnit.DAYS);
//                    }
//                } else {
//                    resultMap.put("alarm", utcTime);
//                    redisTemplate.opsForHash().putAll(redisKey, resultMap);
//                    // 设置过期时间
//                    redisTemplate.expire(redisKey, 2, TimeUnit.DAYS);
//                    isAdd = true;
//                }
//            }
//        } else {
//            // 储存到 redis 中的数据
//            Map<String, String> redisMap = new HashMap<String, String>();
//            if (dataType == 1) {
//                redisMap.put("timing", utcTime);
//            } else if (dataType == 2) {
//                redisMap.put("alarm", utcTime);
//            }
//            redisTemplate.opsForHash().putAll(redisKey, redisMap);
//            // 设置过期时间
//            redisTemplate.expire(redisKey, 2, TimeUnit.DAYS);
//            isAdd = true;
//        }

        return isAdd;
    }


    /**
     * 音频数据存储及识别
     *
     * @param cardKey      采集卡和通道的组合id
     * @param getCardId    采集卡号
     * @param getChannelId 通道号 (手持设备用mac地址当做通道号)
     * @param alarmState   是否报警
     * @param utcTime      事件发生时间
     */
    @Async
    public void recognitionAndpersistence(String cardKey, String getCardId, String getChannelId, byte cardType,int alarmState, String utcTime) {
        log.info("cardKey：" + cardKey);
        // 获得内存中存储的数据
        Map<String, byte[]> dataMap = new HashMap<>();
        // 数据该有的帧数
        int dataNum = 0;
        if (alarmState == 1) {
            dataNum = Constant.ALARM_MIN_FRAMENUMER;
            dataMap = udpMapData.alarmUdpMapGet(cardKey);
        } else if (alarmState == 2) {
            dataNum = Constant.TIMING_MIN_FRAMENUMER;
            // 取出正常的音频数据
            dataMap = udpMapData.udpMapGet(cardKey);
        }
        log.info("--- 数据是否为空 ---");
        // 如果不为空就取出音频数据
        if (dataMap != null && dataMap.size() > dataNum) {
        	log.info("dataMap size = " + dataMap.size());
            // 将解压后的数据放到内存中方便调用
            Map<String, byte[]> credByteMap = new HashMap<>();
            String credByteMapKey = getCardId + "_" + getChannelId;
   
            OpusSdk opusSdk = OpusSdkProvider.getOpusSdk();
            long opusId = OpusSdkProvider.getOpusId();
            // 计算出数据的总长度
            for (int i = 0; i <= Constant.OPUS_FRAME_SUM; i++) {
                if (dataMap.get(String.valueOf(i)) != null && dataMap.get(String.valueOf(i)).length > 0) {
                    byte[] firstFrame = dataMap.get(String.valueOf(i));
                    int finx = 0;
                    for (int j = 0; j < 2; j++) {
                        byte[] ziFirstFrame = new byte[firstFrame.length / 2];
                        for (int h = 0; h < ziFirstFrame.length; h++) {
                            ziFirstFrame[h] = firstFrame[finx];
                            finx++;
                        }
                        short[] pcmShort = new short[Constant.OPUS_DECODER_SHORT_BUFFER_SIZE];
                        // 调用opus进行解压
                        opusSdk.opusDecoder(opusId, ziFirstFrame, pcmShort);
                        // 丢掉开始的80毫秒数据
                        if (i != 0) {
                            byte[] buffer = ByteUtil.toByteArray(pcmShort);
                            if (credByteMap.get(credByteMapKey) != null) {
                                // 当前数组的长度
                                int currentSize = credByteMap.get(credByteMapKey).length;
                                // 当前的数据
                                byte[] currentData = credByteMap.get(credByteMapKey);
                                int finalSize = currentSize + buffer.length;
                                // 最终的数据
                                byte[] finalData = new byte[finalSize];
                                int g = 0;
                                // 放入原始的数据
                                for (byte cc : currentData) {
                                    finalData[g] = cc;
                                    g++;
                                }
                                // 放入新值
                                for (byte cc : buffer) {
                                    finalData[g] = cc;
                                    g++;
                                }
                                credByteMap.put(credByteMapKey, finalData);
                            } else {
                                credByteMap.put(credByteMapKey, buffer);
                            }
                        }
                    }
                }
            }
            // 释放opus
            //opusSdk.destroy(opusId);
            // 最终数据
            byte[] opusByte = credByteMap.get(credByteMapKey);
            
            String fileDic = "/mnt/audiofile/";
            File file = new File(fileDic + UUID.randomUUID().toString()+".wav");
            try {
                FileOutputStream fis = new FileOutputStream(file);
                fis.write(opusByte);
                fis.flush();
                fis.close();
            }catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
            	//存储到kafka
                String soundKey =getCardId+ "_" +getChannelId+ "_" +cardType+ "_" + utcTime;
                log.info("KafkaProducerUtil.saveSound key="+soundKey);
                KafkaProducerUtil.saveSound(soundKey, opusByte);
                //存储到hbase
                MessageEntity msg = new MessageEntity();
                msg.setCardId(Integer.parseInt(getCardId));
                msg.setChannelId(Byte.parseByte(getChannelId));
                msg.setCardType(cardType);
                msg.setOccurTime(Long.parseLong(utcTime));
				HBaseUtil.saveSoudataTimeorder(msg,soundKey, opusByte);
				log.info("存储到hbase");
            } catch (NumberFormatException e1) {
				e1.printStackTrace();
			} catch (IOException e1) {	
				e1.printStackTrace();
			}
            

            // 获得当前时间的时间戳
            /*Date nowDate = new Date();
            int nowDateInt = (int) (nowDate.getTime() / 1000);
            log.info("全部音频长度：" + opusByte.length);
            // 转换成Base64字符串
            BASE64Encoder encode = new BASE64Encoder();
            String pmcBase64 = encode.encode(opusByte);
            
            RestTemplate restTemplate = new RestTemplate();
            MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
            // 音频数据
            map.add("pmcBase64", pmcBase64);
            // 采集卡编号
            map.add("circuitCardNumber", getCardId);
            // 通道号
            map.add("passNumber", getChannelId);
            // 告警时间 alarmState
            map.add("collectionTime", utcTime);
            // 是否报警(1:报警 2:未报警)
            map.add("alarmState", alarmState);
            
            // 调用远程接口
            restTemplate.postForEntity(Constant.RECOGNITION_URL, map, JSONObject.class);            
            log.info("--- 已经调用了识别 ---");
            */
            
        } else {
        	log.info("--- 数据包数长度不够 ---");
        }

    }

}
